#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>

#include <Queueinside.h>
#include <Vector_inside.h>



#define   IN
#define OUT
#define N (6)
#define n_st (3)





struct PQ_Queue
{
    Vec_t* vec;
    int tail ;
    int head ;
   /* void* comp_func(void*, void*);*/
};



/***********************************SingleTreadSchelduler*************************************************/
PQ* PQ_Creat()
{
    PQ* Que=malloc(sizeof(PQ));
    if(Que==NULL)
    {
        printf("CONT_IMPOSSIBLE_ALLOCATE_NEW_CONT");

        return 0;
    }
    Que->vec=Vector_Creat();
    if(Que->vec==NULL)
    {
        printf("CONT_IMPOSSIBLE_ALLOCATE_NEW_CONT");
        return 0;
    }
    Que->tail=0;
    Que->head=0;
    return Que;
}

/*when too many 5 popfront were done, i want to reallocat vector to release the used memory*/
err_PQ PQ_Uppdate(PQ* _oldQue)
{

    Vec_t* newvec=Vector_Creat();
    void* data;
    size_t i=0;
    if(newvec==NULL)
    {
        printf("CONT_IMPOSSIBLE_ALLOCATE_NEW_CONT");
        return 0;
    }
    while(!(err_PQ)Vector_Get(_oldQue->vec,OUT &data,_oldQue->head+i))
    {
        (err_PQ) Vector_Set(_oldQue->vec,0,_oldQue->head+i);
        (err_PQ) Vector_Add(newvec,data);
        ++i;
    }
    free(_oldQue->vec);
    _oldQue->vec=newvec;
    _oldQue->head=0;
    _oldQue->tail=i;
    return 0;
}



err_PQ PQ_Queue_Pushback(PQ* _Que,void* _data)
{
    err_PQ err;
    if(_Que==NULL)
    {
        return CONT_NOT_ACCEPT_A_CONT ;
    }

    err=(err_PQ) Vector_Add(_Que->vec,_data);
    if(err)
    {
        return err;
    }
    ++_Que->tail;
    return 0;
}


/***************************************************************************/

err_PQ Queue_Push_to_index(PQ* _Que,void* _data,size_t _index)
{
    /*Modifining of standard funciton Pubshback to Push by index.*/
        err_PQ err;
    if(_Que==NULL)
    {
        return CONT_NOT_ACCEPT_A_CONT ;
    }
    err=Vector_Add_by_index(_Que->vec, _data,_index+_Que->head);
    if (err)
    {
        return CONT_ADD_BY_INDEX_ERROR;
    }
    ++_Que->tail;
    return 0;
    }

/***************************************************************************************/

err_PQ  PQ_Queue_Popfront(PQ* _Que,OUT void** data)
{
    err_PQ   err;
    if(_Que->tail==_Que->head)
    {
        return CONT_EMPTY_ARRAY_NOTHING_POP;
    }
    /*I want to update vector if head==5*/
    if(5==_Que->head)
    {
        PQ_Uppdate(_Que);
    }

    err=(err_PQ) Vector_Get(_Que->vec,OUT data,_Que->head);
    err=(err_PQ) Vector_Set(_Que->vec,0,_Que->head);/*remove vector pointing on poped front value
    this allow perform delete*/
    if (err)
    {
        return err;
    }
    ++_Que->head;

    return 0;
}

/*show data from index*/
err_PQ  PQ_Showindex(PQ* _Que,OUT void** data,size_t _index)
{
    err_PQ   err;
    if(_Que->tail==_Que->head)
    {
        return CONT_EMPTY_ARRAY_NOTHING_POP;
    }

    err=(err_PQ) Vector_Get(_Que->vec,OUT data,_Que->head+_index);
    if (err)
    {
        return err;
    }

    return 0;
}



void  PQ_Queue_Destroy(PQ* _Que)
{
    Vector_Destroy(_Que->vec);
    free(_Que->vec);
    return;
}

#ifdef PQ_testing
/****************************Testing**************************************************************************/
typedef struct ST_Task ST_Task;

typedef void (*func_ptr) (void);
struct ST_Task
{
    time_t    nextrun;
    void*     userdata;
    int       period;
    func_ptr  func;
};

int PQ_execu(PQ* que_readyfortaskexe)
{
    ST_Task* c;
    PQ_Queue_Popfront(que_readyfortaskexe, &c);
    c->func();
    return 0;
}




void        funcki(void);
void        funcki1(void);
err_PQ      Testing_PQ_Creat_Pushback_Popfront(void);
err_PQ      Testing_Queue_Push_to_index(void);
void Testing_PQ_timing(void);

int main()
{
    Testing_PQ_Creat_Pushback_Popfront();
    Testing_Queue_Push_to_index();

 return 0;
}

err_PQ Testing_PQ_Creat_Pushback_Popfront(void)
{
    ST_Task a,b;
    ST_Task* c;
    PQ* testQ;

/*filling tesing data*/
    a.period=5;
    b.period=10;
    a.func=funcki;
    b.func=funcki1;
    a.func();
    b.func();
    testQ=PQ_Creat();
    PQ_Queue_Pushback(testQ,&a);
    PQ_Queue_Pushback(testQ,&b);
    PQ_execu(testQ);
    PQ_Queue_Popfront(testQ,&c);
    c->func();
    if(c->period==10)
    {
        printf("\n Last expression has to be Second function funcki1  \n");
        return 0;
    }
    return 1;
}

err_PQ Testing_Queue_Push_to_index()
{
    ST_Task                   a,b,c,d,e,Initialpop;
    ST_Task*                  answer;
    PQ*                    testQ;
    int                    i;

/*filling tesing data*/

    Initialpop.period    =0;
    a.period             =5;
    b.period             =10;
    c.period             =15;
    d.period             =20;
    e.period             =25;

    testQ=PQ_Creat();
    PQ_Queue_Pushback(testQ,&Initialpop);/*To change head and verify that all will be ok*/
    PQ_Queue_Popfront(testQ,&Initialpop);

    PQ_Queue_Pushback(testQ,&c);
    PQ_Queue_Pushback(testQ,&e);
    Queue_Push_to_index(testQ,&a,0);
    Queue_Push_to_index(testQ,&d,2);
    Queue_Push_to_index(testQ,&b,1);

    printf("\nList of numbers from 5 to 25 has to appear:\n ");
    for(i=0;i<5;++i)
    {
        PQ_Queue_Popfront(testQ,&answer);
        printf("%d ",answer->period);
        if(i==4)
        {
            printf("\nFunciton Queue_Push_to_index() is O.K.");
            return 0;
        }
    }
    return 2;
}

void funcki(void)
{
    printf("\n First function funcki \n");
}

void funcki1(void)
{
    printf("\n Second function funcki1 \n");
}
#endif /*PQ_testing*/




